from rest_framework.views import APIView
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, ViewSetMixin

from prj002.utils.same_code import SCView, SearchInfoView, get_excel_needed
from prj002.utils.constants import SESSION_DATA
from prj002.serializers import (
    InfoLinkSerializer, SummaryLinkSerializer, StandardLinkSerializer,
    HistoryLinkSerializer, CureLinkSerializer, DiseaseLinkSerializer,
    ExperimentLinkSerializer, SearchSerializer, MobileSerializer,
    ClinicalLinkSerializer, InfoSerializer, CheckStatusSerializer,
    BxrayLinkSerializer,
)
from prj002.models import (
    clinical, cure, disease, experiment,
    info, standard, summary, history, bxray
)

from prj002.pagination import ListInfoPagination
from prj002.permissions import MobileClientPermission, DiffRolePermisssion

from oauth2_provider.contrib.rest_framework import TokenHasScope

from utils.saveexcel import create_excel
from utils.samecode import SCChartView, func_pop_none_value, deny_check
from celery_tasks import tasks


class ChartInfoView(ViewSetMixin, APIView, SCChartView):
    permission_classes = [TokenHasScope, DiffRolePermisssion]
    required_scopes = ['prj002']
    model_ = info.Info


class MobileView(ModelViewSet):
    permission_classes = [TokenHasScope, MobileClientPermission]
    required_scopes = ['prj002']
    serializer_class = MobileSerializer

    def create(self, request, *args, **kwargs):
        data = request.data
        require_key = [
            'info', 'summary', 'history',
            'experiment', 'bxray', 'cure',
            'clinical', 'disease', 'standard'
        ]
        validate_data = func_pop_none_value(data, require_key)

        try:
            serializer = self.get_serializer(data=validate_data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
        except Exception as e:
            return Response({'detail': '信息保存失败', 'error': '{}'.format(e)}, status=400)

        return Response({'detail': '信息保存成功'})


class FileOutView(SearchInfoView):
    serializer_class = InfoSerializer
    queryset = info.Info.objects.order_by('-create_time', '-serial')
    pagination_class = None

    def list(self, request, *args, **kwargs):
        search_data = SESSION_DATA.get('{}'.format(request.user.id))

        if not search_data:
            queryset = self.get_queryset()
        else:
            queryset = self.search_instances(search_data)

        total_data = []

        for obj in queryset:
            data = get_excel_needed(obj)
            total_data.append(data)

        file_url = create_excel(total_data, request.user.id, project_name='prj002')

        return Response({'url': file_url})


class SearchView(SearchInfoView):
    """
    Override .get_queryset() to get instances
    """
    serializer_class = SearchSerializer
    queryset = info.Info.objects.order_by('-create_time', '-serial')

    def get_queryset(self):
        request_data = self.request.data

        SESSION_DATA['{}'.format(self.request.user.id)] = request_data

        self.serializer_class = InfoLinkSerializer

        return self.search_instances(request_data)


class InfoView(SCView):
    """
    get([list, retrieve]):
    1. Return all info instance
    2. Return the info instance by id

    post(create):
    Save a info instance and Return it.

    patch(partial_update):
    Update the info instance and Return it.

    delete(destroy):
    Delete the info instance by id.
    """
    view_name = 'info'
    serializer_class = InfoLinkSerializer
    pagination_class = ListInfoPagination
    queryset = info.Info.objects.order_by('-create_time', '-serial')
    set_session_data = True    # set SESSION_DATA value is None [when user request index]

    def get_serializer_class(self):
        if self.action == 'check':
            return CheckStatusSerializer

        return self.serializer_class

    @action(detail=True, methods=['post'])
    def check(self, request, pk, *args, **kwargs):
        try:
            info_object = info.Info.objects.get(pk=pk)
        except info.Info.DoesNotExist:
            return Response({'detail': '该记录不存在'}, status=404)

        data = request.data
        before_status = info_object.check_status
        after_status = data.get('check_status')
        user = request.user
        info_user = info_object.owner

        deny_check(before_status, user, after_status, info_user, project_name='prj002')

        for key, value in data.items():
            if hasattr(info_object, key):
                setattr(info_object, key, value)

        info_object.save()

        # celery 处理
        # 1. 未提交 => 已提交: 保存Excel
        if before_status == '未提交' and after_status == '已提交':
            excel_data = get_excel_needed(info_object)
            tasks.celery_save_excel.delay(excel_data, info_object.owner.email, serial=info_object.serial, project_name='prj002')

        # 2. 审核不通过 => 已提交: 保存至数据库

        # self.get_serializer => check status serializer class
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        # self.serializer_class => info serializer class
        info_serializer = self.serializer_class(info_object, context={'request': request})
        return Response(info_serializer.data)


class StandardView(SCView):
    serializer_class = StandardLinkSerializer
    queryset = standard.Standard.objects.order_by('-create_time', '-pk')


class SummaryView(SCView):
    serializer_class = SummaryLinkSerializer
    queryset = summary.Summary.objects.order_by('-create_time', '-pk')


class HistoryView(SCView):
    serializer_class = HistoryLinkSerializer
    queryset = history.History.objects.order_by('-create_time', '-pk')


class ExperimentView(SCView):
    serializer_class = ExperimentLinkSerializer
    queryset = experiment.Experiment.objects.order_by('-create_time', '-pk')


class BxrayView(SCView):
    serializer_class = BxrayLinkSerializer
    queryset = bxray.Bxray.objects.order_by('-create_time', '-pk')


class CureView(SCView):
    serializer_class = CureLinkSerializer
    queryset = cure.Cure.objects.order_by('-create_time', '-pk')


class ClinicalView(SCView):
    serializer_class = ClinicalLinkSerializer
    queryset = clinical.Clinical.objects.order_by('-create_time', '-pk')


class DiseaseView(SCView):
    serializer_class = DiseaseLinkSerializer
    queryset = disease.Disease.objects.order_by('-create_time', '-pk')
